/*
 * Copyright (c) 2023 Beijing HuaQing YuanJian Education Technology Co., Ltd
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "wifi_device.h"
#include "lwip/netifapi.h"
#include "mywifi.h"

static int g_connectSuccess = 0;
#define SELECT_WLAN_PORT "wlan0"
static struct netif *g_lwip_netif = NULL;
char g_IP_Addr[20] = {0}; // 连接wifi热点之后，获取到的IP地址

#if 0
osThreadId_t Task1_ID; // 任务1设置为低优先级任务
#define TASK_STACK_SIZE (1024 * 10)
#endif

#define WIFI_SSID "cdhqyj-4floor"
#define WIFI_PAWD "cdhq0900"

static void myPrintLinkedInfo(WifiLinkedInfo* info)
{
    char ipAddr[20] = {0};

    if (NULL == info) 
    {
        printf("link info is NULL.\n");
        return;
    }

    static char macAddress[32] = {0};
    unsigned char* mac = info->bssid;
    snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac[0], mac[0], mac[2], mac[3], mac[4], mac[5]);
    snprintf(ipAddr, sizeof(ipAddr),"%u.%u.%u.%u\0",(info->ipAddress&0xff000000)>>24,(info->ipAddress&0x00ff0000)>>16,(info->ipAddress&0x0000ff00)>>8,info->ipAddress&0x000000ff);
    printf("Wifi link:bssid: %s, rssi: %d, connState: %d, reason: %d, ssid: %s, ipAddr: %s\r\n",
        macAddress, info->rssi, info->connState, info->disconnectedReason, info->ssid, ipAddr);
}

//连接状态改变时打印
static void myWifiConectionChanged(int state, WifiLinkedInfo *info)
{
    myPrintLinkedInfo(info);

    printf("state = %X\r\n", state);
    if (WIFI_STATE_AVALIABLE == state)
    {
        g_connectSuccess = 1;
    }
    else
    {
        g_connectSuccess = 0;
    }
}

static void myWifiScanStateChanged(int state, int size)
{
    printf("state = %X, size = %d\r\n",state, size);
}

/**
 * 获取WiFi的IP地址
 **/
void getWifiIp(struct netif *netif, char *ip)
{
    int ret;
    if (netif == NULL) {
        return;
    }

    ip4_addr_t ipAddr;
    ip4_addr_t netMask;
    ip4_addr_t gateWay;

    ret = netifapi_netif_get_addr(netif, &ipAddr, &netMask, &gateWay);
    if (ret == 0) {
        inet_ntop(AF_INET, &ipAddr, ip, INET_ADDRSTRLEN);
    }
}

int connectToWifi(char *ssid, char *key)
{
    int ret = ERROR_WIFI_UNKNOWN;
    WifiEvent event = {0};
    WifiDeviceConfig config = {0};
    int networkId = -1;
    int Timeout = 10;

    printf("Start to connect is wifi\r\n");
    if (NULL ==ssid || NULL == key)
    {
        printf("ssid is NULL or key is NULL!\r\n");
        return ERROR_WIFI_INVALID_ARGS;
    }
    
    event.OnWifiConnectionChanged = myWifiConectionChanged;
    event.OnWifiScanStateChanged = myWifiScanStateChanged;

    //注册wifi事件,不能重入
    ret = RegisterWifiEvent(&event);
    if (WIFI_SUCCESS != ret)
    {
        printf("Register wifi info failed, ret is %d.\n", ret);
        return ret;
    }

    //使能wifi
    ret = EnableWifi();
    if (WIFI_SUCCESS != ret)
    {
        printf("Enable wifi failed, ret is %d.\n", ret);
        UnRegisterWifiEvent(&event);
        return ret;
    }
    
    //查看wifi是否激活
    ret = IsWifiActive();
    if (WIFI_STA_ACTIVE != ret)
    {
        printf("Wifi is not active, ret is %d.\n", ret);
        DisableWifi();
        UnRegisterWifiEvent(&event);
        return ret;
    }

    strcpy(config.ssid, ssid);
    strcpy(config.preSharedKey, key);
    config.securityType = WIFI_SEC_TYPE_PSK;
    printf("ssid is %s , key is %s!\r\n", config.ssid, config.preSharedKey);
    //添加wifi信息
    ret = AddDeviceConfig(&config, &networkId);
    if (WIFI_SUCCESS != ret)
    {
        printf("Add Wifi config failed, ret is %d.\n", ret);
        DisableWifi();
        UnRegisterWifiEvent(&event);
        return ret;
    }

    //连接wifi
    g_connectSuccess = 0;
    ret = ConnectTo(networkId);
    if (WIFI_SUCCESS != ret)
    {
        printf("ConnectTo(%d) failed, ret is %d.\n", networkId, ret);
        DisableWifi();
        UnRegisterWifiEvent(&event);
        return ret;
    }
    
    printf("Wait for wifi connect");
    while (!g_connectSuccess) { // wait until connect to AP
        sleep(1);
        printf(".");
        Timeout--;
        if (0 == Timeout)
        {
            //超时
            printf("\nTime out for wifi, need reload.\n");
            Disconnect();
            DisableWifi();
            UnRegisterWifiEvent(&event);
            return ERROR_WIFI_NOT_AVAILABLE;
        }
    }
    Timeout = 10;
    printf("\n Wifi connect success: %d\r\n", g_connectSuccess);

    //获取IP
    g_lwip_netif = netifapi_netif_find(SELECT_WLAN_PORT);
    // 启动DHCP
    if (g_lwip_netif) {
        ret = netifapi_dhcp_start(g_lwip_netif);
        if(ERR_OK != ret)
        {
            printf("Start dhcp failed., ret is %d\n", ret);
        }
    }

    // 等待DHCP
    for (;;) {
        if (netifapi_dhcp_is_bound(g_lwip_netif) == ERR_OK) {
            getWifiIp(g_lwip_netif, g_IP_Addr);
            printf("Connect wifi IP addr: %s.\r\n", g_IP_Addr);
            break;
        }
        printf("#");
        Timeout--;
        if (Timeout == 0) {
            // 超时
            Disconnect();
            DisableWifi();
            UnRegisterWifiEvent(&event);
            return ERROR_WIFI_BUSY;
        }
        sleep(1);
    }
    return WIFI_SUCCESS;
}

#if 0
void Task1(void)
{
    int result;
    result = connectToWifi(WIFI_SSID, WIFI_PAWD);
    printf("Connect wifi %d.\n", result);
    while (1) {
        sleep(1); // 1 s
    }
}
static void network_wifi_connect(void)
{
    printf("Enter network_wifi_connect()!\r\n");
    osThreadAttr_t options;
    options.name = "thread_1";
    options.attr_bits = 0;
    options.cb_mem = NULL;
    options.cb_size = 0;
    options.stack_mem = NULL;
    options.stack_size = TASK_STACK_SIZE;
    options.priority = osPriorityNormal;

    Task1_ID = osThreadNew((osThreadFunc_t)Task1, NULL, &options);
    if (Task1_ID != NULL) {
        printf("ID = %d, Create Task1_ID is OK!\r\n", Task1_ID);
    }
}
SYS_RUN(network_wifi_connect);
#endif